﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace ESoft.Core.Util.Extensions
{
    public static class EnumerableExtensions
    {
        /// <summary>
        ///     Joins as string.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="separator">The separator.</param>
        /// <returns>System.String.</returns>
        public static string JoinAsString(this IEnumerable<string> source, string separator = ",")
        {
            return string.Join(separator, source.OpenSafe());
        }

        /// <summary>
        ///     Joins as string.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="separator">The separator.</param>
        /// <returns>System.String.</returns>
        public static string JoinAsString<T>(this IEnumerable<T> source, string separator = ",")
        {
            return string.Join(separator, source.OpenSafe());
        }

        /// <summary>
        /// Joins as string.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="selector">The selector.</param>
        /// <param name="separator">The separator.</param>
        /// <returns>System.String.</returns>
        public static string JoinAsString<T>(this IEnumerable<T> source, Func<T, string> selector = null,
            string separator = ",")
        {
            selector = selector ?? ((T t) => t.ToString());
            return string.Join(separator,(from t in source.OpenSafe() where t!=null select t).Select(selector));
        }

        /// <summary>
        ///     如果condition条件为true根据predicate过滤数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="condition">if set to <c>true</c> [condition].</param>
        /// <param name="predicate">The predicate.</param>
        /// <returns>IEnumerable&lt;T&gt;.</returns>
        public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, bool condition, Func<T, bool> predicate)
        {
            return condition ? source.OpenSafe().Where(predicate) : source;
        }

        /// <summary>
        ///     如果condition条件为true根据predicate过滤数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="condition">if set to <c>true</c> [condition].</param>
        /// <param name="predicate">The predicate.</param>
        /// <returns>IEnumerable&lt;T&gt;.</returns>
        public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, bool condition,
            Func<T, int, bool> predicate)
        {
            return condition ? source.OpenSafe().Where(predicate) : source;
        }

        /// <summary>
        ///     判断集合是否为null或空
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <returns><c>true</c> if [is null or empty] [the specified source]; otherwise, <c>false</c>.</returns>
        public static bool IsNullOrEmpty<T>(this IEnumerable<T> source)
        {
            return source == null || !source.Any();
        }

        public static string Uniquify(this IEnumerable<string> inputStrings, string targetString)
        {
            string uniqueString = targetString;
            int num = 0;
            while (inputStrings.OpenSafe().Any((string n) => string.Equals(n, uniqueString, StringComparison.Ordinal)))
            {
                uniqueString = targetString + ++num;
            }
            return uniqueString;
        }

        /// <summary>
        /// 集合遍历操作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ts">The ts.</param>
        /// <param name="action">The action.</param>
        public static void Each<T>(this IEnumerable<T> ts, Action<T, int> action)
        {
            int num = 0;
            foreach (T current in ts.OpenSafe())
            {
                action(current, num++);
            }
        }

        /// <summary>
        /// 集合遍历操作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ts">The ts.</param>
        /// <param name="action">The action.</param>
        public static void Each<T>(this IEnumerable<T> ts, Action<T> action)
        {
            foreach (var current in ts.OpenSafe())
            {
                action(current);
            }
        }

        /// <summary>
        /// 集合遍历操作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="S"></typeparam>
        /// <param name="ts">The ts.</param>
        /// <param name="action">The action.</param>
        public static void Each<T, S>(this IEnumerable<T> ts, Func<T, S> action)
        {
            foreach (var current in ts.OpenSafe())
            {
                action(current);
            }
        }


        /// <summary>
        ///     确保集合非null
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <returns>IEnumerable&lt;T&gt;.</returns>
        public static IEnumerable<T> OpenSafe<T>(this IEnumerable<T> source)
        {
            if (source == null)
                return Enumerable.Empty<T>();

            return source;
        }

        /// <summary>
        ///     集合去重复
        /// </summary>
        /// <typeparam name="TSource">The type of the t source.</typeparam>
        /// <typeparam name="TKey">The type of the t key.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="keySelector">The key selector.</param>
        /// <returns>IEnumerable&lt;TSource&gt;.</returns>
        public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            return source.OpenSafe().GroupBy(keySelector).Select(group => group.First());
        }

        /// <summary>
        ///     keyvaluepair键值对集合转字典
        /// </summary>
        /// <typeparam name="TKey">The type of the t key.</typeparam>
        /// <typeparam name="TValue">The type of the t value.</typeparam>
        /// <param name="source">The source.</param>
        /// <returns>IDictionary&lt;TKey, TValue&gt;.</returns>
        public static IDictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source)
        {
            return source.OpenSafe().ToDictionary(kv => kv.Key, kv => kv.Value);
        }

        /// <summary>
        /// 集合尾部追加内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="tail">The tail.</param>
        /// <returns>IEnumerable&lt;T&gt;.</returns>
        public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] tail)
        {
            return source.OpenSafe().Concat(tail.OpenSafe());
        }

        /// <summary>
        /// 在集合项前添加内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="head">The head.</param>
        /// <returns>IEnumerable&lt;T&gt;.</returns>
        public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, params T[] head)
        {
            return head.OpenSafe().Concat(source.OpenSafe());
        }

        /// <summary>
        /// ICollection追加内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="items">The items.</param>
        public static void AddRange<T>(this ICollection<T> source, IEnumerable<T> items)
        {
            foreach (var item in items.OpenSafe())
            {
                source.Add(item);
            }
        }
    }
}